package configure

import (
	"fmt"
	config "gin_api/config/configure"
	"gin_api/core/storage"
	"gin_api/global"
	"gopkg.in/yaml.v2"
	"io/ioutil"
	"reflect"
	"strings"
)

// ConfigPath 配置文件目录
const ConfigPath = "./config"

// Init 初始化配置
func Init() {
	configures := make(global.Configure, 0)

	// 从目录中遍历配置文件
	files := storage.Files(ConfigPath)

	for _, file := range files {
		if strings.HasSuffix(file.FilePath, ".yml") {
			// 读取YAML配置文件
			maps := make(global.Configure, 0)
			filename := file.FileInfo.Name()
			_ = ReadConfig(filename, &maps)
			configures[filename[:len(filename)-4]] = maps
		}
	}

	global.CONFIG = configures
}

/**
 * init 加载配置文件
 * 通过反射的方式，依次从configure中，加载配置信息
 */
/*func InitConfigWithStruct() {
	configures := configure.Configure{}
	getType := reflect.TypeOf(configures)
	for i := 0; i < getType.NumField(); i++ {
		fieldStruct := getType.Field(i)
		// 标签
		config := fieldStruct.Tag.Get("config")
		if config == "" {
			// 未设置标签，默认为struct名
			config = strings.ToLower(fieldStruct.Name)
		}
		// 实例化config struct
		c := reflect.New(fieldStruct.Type).Elem().Interface()
		// 获取配置信息
		_ = core.Config(config, &c)
	}
}*/

// InitConfigWithInterface 通过反射，获取配置到struct
func InitConfigWithInterface() {
	configures := &config.Configure{}
	getValue := reflect.ValueOf(configures)
	getType := reflect.TypeOf(configures)
	if getType.Kind() == reflect.Ptr {
		getType = getType.Elem()
		getValue = getValue.Elem()
	}
	for i := 0; i < getType.NumField(); i++ {
		if i > 0 {
			return
		}
		fieldStruct := getType.Field(i)
		valueStruct := getValue.Field(i)
		tag := fieldStruct.Tag.Get("conf")
		if tag == "" {
			tag = strings.ToLower(fieldStruct.Name)
		}
		// 实例化struct
		// c := reflect.New(fieldStruct.Type).Elem().Interface()
		c := valueStruct.Interface()
		_ = ReadConfig(fmt.Sprintf("%s.yml", tag), c)
		//fmt.Printf("%#v\n", c)
		valueStruct.Set(reflect.ValueOf(c))

	}
	fmt.Printf("配置：%#v\n", configures)
}

func Read(filename string, out interface{}) interface{} {
	err := ReadConfig(filename, out)
	if err != nil {
		return out
	}
	return out
}

// ReadConfig 读取配置文件
func ReadConfig(filename string, out interface{}) error {
	file := fmt.Sprintf("%s/%s", ConfigPath, filename)
	content, err := ioutil.ReadFile(file)
	if err != nil {
		return err
	}

	err = yaml.Unmarshal(content, out)
	if err != nil {
		return err
	}

	return nil
}

func GetString(key string) string {
	val := Get(key)
	if val == nil {
		return ""
	}
	return val.(string)
}

func GetBool(key string) bool {
	val := Get(key)
	if val == nil {
		return false
	}
	return val.(bool)
}

func GetInt(key string) int {
	val := Get(key)
	if val == nil {
		return 0
	}
	return val.(int)
}

func GetMap(key string) global.Configure {
	val := Get(key)
	if val == nil {
		return nil
	}
	return val.(global.Configure)
}

// Get 获取配置
func Get(key string) interface{} {
	keys := strings.Split(key, ".")
	configs := global.CONFIG
	return search(configs, keys)
}

// GetDefault 设定默认值，获取配置
func GetDefault(key string, value interface{}) interface{} {
	config := Get(key)
	if config == nil {
		config = value
	}
	return config
}

// search 检索配置
func search(source global.Configure, path []string) interface{} {
	if len(path) == 0 {
		return source
	}

	next, ok := source[path[0]]
	if ok {
		// Fast path
		if len(path) == 1 {
			return next
		}

		switch next.(type) {
		case global.Configure:
			return search(next.(global.Configure), path[1:])
		case map[string]interface{}:
			return search(next.(global.Configure), path[1:])
		case map[interface{}]interface{}:
			return search(next.(global.Configure), path[1:])
		default:
			return nil
		}
	}
	return nil
}
